// -*-mode:c++; coding:utf-8-*-

#ifndef _XBASE_TABLE_SCHEMA_HPP_
#define _XBASE_TABLE_SCHEMA_HPP_

#include <map>
#include <ext/hash_map>

#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>

// TODO: 尽量将该头文件去掉
#include <protocol.hpp>		// for table_info
#include <stringable.hpp>

namespace xbase
{


	// 表结构
	// 暂为对table_info的封装，并逐步取代它
	class table_schema
		: public stringable
	{
	public:
		typedef boost::shared_ptr<table_schema> pointer;
		typedef boost::weak_ptr<table_schema> weak_pointer;

	public:

		struct family_info
		{
			typedef boost::shared_ptr<family_info> pointer;

			family_info()
				: m_family_name()
				, m_max_num_version(0)
				, m_max_ttl(0)
				, m_dead_time(0) {}

			family_info(const std::string &p_family_name,
				    uint32_t p_max_num_version,
				    uint32_t p_max_ttl,
				    uint32_t p_dead_time)
				: m_family_name(p_family_name)
				, m_max_num_version(p_max_num_version)
				, m_max_ttl(p_max_ttl)
				, m_dead_time(p_dead_time)
				{
				}
      
			std::string m_family_name;

			uint32_t m_max_num_version;
			uint32_t m_max_ttl;
			uint32_t m_dead_time;
		};

		struct group_info
		{
			typedef boost::shared_ptr<group_info> pointer;
			typedef boost::weak_ptr<group_info> weak_pointer;

			group_info(const std::string &p_group_name,
				   uint32_t p_compress_method,
				   uint32_t p_cache_rate,
				   uint32_t p_block_size,
				   uint32_t p_max_num_sstable,
				   uint32_t p_max_size_sstable,
				   uint32_t p_max_size_memtable)
				: m_group_name(p_group_name)
				, m_compress_method(p_compress_method)
				, m_cache_rate(p_cache_rate)
				, m_block_size(p_block_size)
				, m_max_num_sstable(p_max_num_sstable)
				, m_max_size_sstable(p_max_size_sstable)
				, m_max_size_memtable(p_max_size_memtable)
				, m_max_cache_size(0)
				{
					m_max_cache_size = calc_max_cache_size();
				}

			std::string m_group_name;

			uint32_t m_compress_method;
			uint32_t m_cache_rate;
			uint32_t m_block_size;
			uint32_t m_max_num_sstable;
			uint32_t m_max_size_sstable;
			uint32_t m_max_size_memtable;

			uint32_t m_max_cache_size;

			uint32_t calc_max_cache_size() const
				{
					// 用uint64_t是避免相乘后数值溢出
					uint64_t _tmp = m_max_size_sstable;
					_tmp = _tmp * m_cache_rate; // [0,100]
					_tmp = _tmp / 100;
					return static_cast<uint32_t>(_tmp);
				}
		};

	public:
		typedef __gnu_cxx::hash_map<std::string, group_info::pointer> group_map_type; // group name -> group info
		typedef __gnu_cxx::hash_map<std::string, family_info::pointer> family_map_type; // family name -> family info

		typedef std::map<family_info::pointer, group_info::pointer> family_group_map_type; // family info -> group info
		typedef std::multimap<group_info::pointer, family_info::pointer> group_family_map_type; // group info -> family info

	public:
		//table_schema() {}
		//~table_schema() {}

		explicit
		table_schema(const table_info &p_table);

		// 失败返回空指针
		group_info::pointer get_group_info(const std::string &p_group_name) const;

		std::string which_group(const std::string &p_family_name) const;

		void list_group(std::vector<std::string> &p_list) const;
		void list_family(std::map<std::string, table_schema::family_info> &p_list,
				 const std::string &p_group_name) const;

		size_t group_number() const {
			return m_groups.size();
		}

		bool has_group(const std::string &p_group_name) const
			{
				return m_group_map.find(p_group_name) != m_group_map.end();
			}
		
		bool has_family(const std::string &p_family_name) const
			{
				return m_family_map.find(p_family_name) != m_family_map.end();
			}

		std::string table_name() const
			{
				return m_table_name;
			}

		std::string to_string() const;

	private:
		table_schema (const table_schema &);
		table_schema &operator= (const table_schema &);
		
	private:
		// 该类只提供读操作，所以无须加锁
		std::string m_table_name;
		std::vector<group_info::pointer> m_groups;
		std::vector<family_info::pointer> m_families;

		group_map_type m_group_map;
		family_map_type m_family_map;

		family_group_map_type m_family_group_map;
		group_family_map_type m_group_family_map;
	};
	
} // namespace xbase

#endif	// _XBASE_TABLE_SCHEMA_HPP_
